using System;
using System.Collections.Generic;
using System.IO;
using JmShared;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Net.NetworkInformation;
using System.Globalization;
using System.Security.Cryptography;
using NetworkCommsDotNet;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Linq;
using System.Reflection;
using Gtk;

namespace JiveMessengerLinux
{
	public static class StaticMethods
	{


		public static string[] GetPhysicalAddresses()
		{
			var result = new List<string>();
			NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
			foreach (NetworkInterface adapter in interfaces)
			{
				PhysicalAddress address = adapter.GetPhysicalAddress();
				byte[] bytes = address.GetAddressBytes();
				if (bytes.Length == 0) continue;
				
				var mac = new StringBuilder();
				for (int i = 0; i < bytes.Length; i++)
				{
					mac.Append(bytes[i].ToString("X2"));
					if (i != bytes.Length - 1) mac.Append("-");
				}
				
				result.Add(mac.ToString());
			}
			return result.ToArray();
		}
		private static readonly char[] HexDigits = {
			'0', '1', '2', '3', '4', '5', '6', '7',
			'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
		//public static string PrettyName(UserInfo u)
		//{
		//    return String.IsNullOrEmpty(u.NickName) ? u.UserName : u.NickName;
		//}
		
		//public static List<string> SplitStringByLength(string str, int chunkSize)
		//{
		//    return Enumerable.Range(0, str.Length / chunkSize)
		//        .Select(i => str.Substring(i * chunkSize, chunkSize)).ToList();
		//}
		public static bool ValidateEmoticonShortcut(string str, out string error)
		{
			//error = "";
			//List<string> keys = StaticSettings.GetEmoticons(Client.CurrentUserInfo, true, true).Keys.ToList();
			//if (str.Length == 1)
			//{
			//    error = "Minimum 2 characters";
			//    return false;
			//}
			//if (str.Length > 10)
			//{
			//    error = "Max 10 characters";
			//    return false;
			//}
			//if (keys.Any(k => k.Contains(str)))
			//{
			//    error = "Shortcut already in use or conflicted";
			//    return false;
			//}
			//return true;
			return ValidateEmoticonShortcut(str, "", out error);
		}
		public static string GetEmbeddedStringResource(string resourceName)
		{
			var assembly = Assembly.GetExecutingAssembly();

			
			using (Stream stream = assembly.GetManifestResourceStream(resourceName))
				using (StreamReader reader = new StreamReader(stream))
			{
				string result = reader.ReadToEnd();
				return result;
			}
		}
		public static bool ValidateEmoticonShortcut(string str,string exludeShortcut, out string error)
		{
			error = "";
			List<string> keys = StaticSettings.GetEmoticons(Client.CurrentUserInfo, true, true).Keys.ToList();
			if (!String.IsNullOrEmpty(exludeShortcut))
			{
				if (keys.Contains(exludeShortcut))
					keys.Remove(exludeShortcut);
			}
			if (str.Length == 1)
			{
				error = "Minimum 2 characters";
				return false;
			}
			if (str.Length > 10)
			{
				error = "Max 10 characters";
				return false;
			}

            if (keys.FindAll(x => x.Contains(str)).Count > 0)
			{
				error = "Shortcut already in use or conflicted";
				return false;
			}
			return true;
		}
		public static List<string> SplitLongMessage(string str, int chunkSize)
		{
			if (str.Length < chunkSize)
				return null;
			int totalLength = str.Length;
			List<string> strList = new List<string>();
			int i = 0;
			while (true)
			{
				if ((totalLength - i) < chunkSize)
				{
					strList.Add(str.Substring(i, totalLength - i));
					break;
				}
				string sub = str.Substring(i, chunkSize);
				int lastSpaceIndex = sub.LastIndexOf(' ');
				if (lastSpaceIndex == -1)
					lastSpaceIndex = 400;
				
				strList.Add(str.Substring(i, lastSpaceIndex));
				i += lastSpaceIndex;
				
				
			}
			return strList;
		}
		public static string GenerateLogName(string loggedInUserName,string logName, string folderPath)
		{
			string validatedName = logName;
			int tries = 1;
			
			DirectoryInfo saveDir = new DirectoryInfo(CombinePath(folderPath ,loggedInUserName ));
			if (!saveDir.Exists)
				saveDir.Create();
			
			while (File.Exists(CombinePath(saveDir,Path.ChangeExtension(validatedName,".xml"))))
			{
				FileInfo fi = new FileInfo(CombinePath(saveDir,Path.ChangeExtension(validatedName,".xml")));
				if (fi.Length < 5000 * 1024)
				{
					if (!File.Exists(CombinePath(saveDir,string.Format("{0} ({1}){2}", Path.GetFileNameWithoutExtension(logName), tries + 1, Path.GetExtension(logName)))))
						return fi.FullName;
				}
				validatedName = string.Format("{0} ({1}){2}", Path.GetFileNameWithoutExtension(logName), tries++, Path.GetExtension(logName));
			}
			return CombinePath(saveDir,Path.ChangeExtension(validatedName,".xml"));
		}
		
		public static int RandomNumber(int from, int to)
		{
			Random r = new Random(DateTime.Now.Millisecond);
			return r.Next(from, to);
			
		}
		public static string CombinePath(params object[] values)
		{
			string path = "";
			foreach (var str in values)
			{
				path += str.ToString().TrimStart(Path.DirectorySeparatorChar).EndsWith(Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture)) ? str : str.ToString() + Path.DirectorySeparatorChar;
			}
			
			return path.TrimEnd(Path.DirectorySeparatorChar);
		}
		//public static String EregiReplace(String pat, String newStr, String input)
		//{
		//    Regex reg = new Regex(pat, RegexOptions.IgnoreCase | RegexOptions.None);
		//    MatchCollection mcol = reg.Matches(input);
		//    if (mcol.Count > 0)
		//    {
		//        foreach (Match m in mcol)
		//        {
		//            String newStrFmt = newStr;
		//            for (int i = 0; i < m.Groups.Count; i++)
		//            {
		//                try
		//                {
		//                    newStrFmt = newStrFmt.Replace("\\" + i, m.Groups[i].Captures[0].Value);
		//                }
		//                catch
		//                {
		//                    newStrFmt = newStrFmt.Replace("\\" + i, "");
		//                }
		//            }
		
		//            input = input.Replace(m.Groups[0].Captures[0].Value, newStrFmt);
		//        }
		//    }
		//    return input.Trim();
		//}
		public static string LoginInfoToString(LoginInfo input)
		{
			MemoryStream stream = new MemoryStream();
			DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(LoginInfo));
			ser.WriteObject(stream, input);
			return Encoding.UTF8.GetString(stream.ToArray());
		}
		//public static LoginInfo StringToLoginInfo(string input)
		//{
		//    if (String.IsNullOrEmpty(input))
		//        return new LoginInfo();
		//    MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(input));
		//    DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(LoginInfo));
		//    return (LoginInfo)ser.ReadObject(stream);
		//}
        //public static string ContactEmoticonToString(ContactEmoticon input)
        //{
        //    MemoryStream stream = new MemoryStream();
        //    DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ContactEmoticon));
        //    ser.WriteObject(stream, input);
        //    return Encoding.UTF8.GetString(stream.ToArray());
        //}
        public static string ObjectToString<T>(object input)
        {
            MemoryStream stream = new MemoryStream();
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
            ser.WriteObject(stream, input);
            byte[] bytes = stream.ToArray();
            return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
        }
		public static ContactEmoticon StringToContactEmoticon(string input)
		{
			if (String.IsNullOrEmpty(input))
				return new ContactEmoticon();
			MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(input));
			DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ContactEmoticon));
			return (ContactEmoticon)ser.ReadObject(stream);
		}
		public static string DictionaryToString<TK, TV>(Dictionary<TK, TV> input)
		{
			MemoryStream stream = new MemoryStream();
			DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Dictionary<TK, TV>));
			
			ser.WriteObject(stream, input);
			string str = Encoding.UTF8.GetString(stream.ToArray());
			stream.Dispose();
			return str;
		}
		public static string ListToString<T>(List<T> input)
		{
			MemoryStream stream = new MemoryStream();
			DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<T>));
			ser.WriteObject(stream, input);
			string str = Encoding.UTF8.GetString(stream.ToArray());
			stream.Dispose();
			return str;
		}
		public static Dictionary<TK, TV> StringToDictionary<TK, TV>(string input)
		{
			if (String.IsNullOrEmpty(input))
				return new Dictionary<TK, TV>();
			MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(input));
			
			DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Dictionary<TK, TV>));
			Dictionary<TK,TV> dic = (Dictionary<TK, TV>)ser.ReadObject(stream);
			stream.Dispose();
			return dic;
		}
		public static List<T> StringToList<T>(string input)
		{
			if (String.IsNullOrEmpty(input))
				return new List<T>();
			MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(input));
			DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<T>));
			List<T> lst = (List<T>)ser.ReadObject(stream);
			stream.Dispose();
			return lst;
		}
		/// <summary>Returns true if the current application has focus, false otherwise</summary>
		public static bool ApplicationIsActivated()
		{
			var activatedHandle = GetForegroundWindow();
			if (activatedHandle == IntPtr.Zero)
			{
				return false;       // No window is currently activated
			}
			
			var procId = Process.GetCurrentProcess().Id;
			int activeProcId;
			GetWindowThreadProcessId(activatedHandle, out activeProcId);
			
			return activeProcId == procId;
		}
		
		public static string FileNameFriendly(string n)
		{
			n = n.Replace("*", "~");
			n = n.Replace("|", "-");
			n = n.Replace(@"\", "'");
			n = n.Replace("/", "_");
			n = n.Replace(":", ".");
			n = n.Replace("<", "(");
			n = n.Replace(">", ")");
			n = n.Replace("?", "^");
			n = n.Replace('"'.ToString(CultureInfo.InvariantCulture), "");
			n = n.Trim();
			return n;
		}
		
		public static string EncodePassword(string password)
		{
			return string.Join("", SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(password)).Select(x => x.ToString("X2"))).ToLower();
		}
//		public static ImageSource BitmapFromUri(Uri source)
//		{
//			var bitmap = new BitmapImage();
//			
//			try
//			{
//				bitmap.BeginInit();
//				bitmap.UriSource = source;
//				bitmap.CacheOption = BitmapCacheOption.OnLoad;
//				bitmap.EndInit();
//			}
//			catch (Exception err)
//			{
//				bitmap = null;
//				NetworkComms.Logger.ErrorException("Error loading image source", err);
//				
//			}
//			return bitmap;
//		}
        /// <summary>
        /// Attempts to grab a lock for a file stream, returns null if file is in use.
        /// </summary>
        /// <returns>The for file.</returns>
        /// <param name="fullPath">Full path.</param>
        /// <param name="mode">Mode.</param>
        /// <param name="access">Access.</param>
		public static FileStream WaitForFile(string fullPath, FileMode mode, FileAccess access)
		{
			if (!File.Exists(fullPath) && (mode == FileMode.Open || mode == FileMode.Truncate || mode == FileMode.Append))
				throw new FileNotFoundException(fullPath);
			int numTries = 0;
			while (true)
			{
				++numTries;
				try
				{
					// Attempt to open the file exclusively.
					FileStream fs = new FileStream(fullPath,
					                               mode, access,
					                               FileShare.None, 100);
					
					//  fs.ReadByte();
					
					// If we got this far the file is ready
					return fs;
					
				}
				catch (Exception err)
				{
					
					if (numTries > 100)
					{
						NetworkComms.Logger.ErrorException("Timed out waiting for file lock", err);
						return null;
					}
					
					// Wait for the lock to be released
					System.Threading.Thread.Sleep(10);
				}
			}
			
		}
		//public static IPEndPoint GetIPEndPointFromHostName(string hostName, int port, bool throwIfMoreThanOneIP)
		//{
		//    var addresses = System.Net.Dns.GetHostAddresses(hostName);
		//    if (addresses.Length == 0)
		//    {
		//        throw new ArgumentException(
		//            "Unable to retrieve address from specified host name.",
		//            "hostName"
		//        );
		//    }
		//    else if (throwIfMoreThanOneIP && addresses.Length > 1)
		//    {
		//        throw new ArgumentException(
		//            "There is more that one IP address to the specified host.",
		//            "hostName"
		//        );
		//    }
		//    return new IPEndPoint(addresses[0], port); // Port gets validated here.
		//}
//		public static Color HexStringToColor(String hex)
//		{
//			
//			//remove the # at the front
//			hex = hex.Replace("#", "");
//			
//			byte a = 255;
//			byte r = 255;
//			byte g = 255;
//			byte b = 255;
//			
//			int start = 0;
//			
//			//handle ARGB strings (8 characters long)
//			if (hex.Length == 8)
//			{
//				a = byte.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
//				start = 2;
//			}
//			
//			//convert RGB characters to bytes
//			r = byte.Parse(hex.Substring(start, 2), System.Globalization.NumberStyles.HexNumber);
//			g = byte.Parse(hex.Substring(start + 2, 2), System.Globalization.NumberStyles.HexNumber);
//			b = byte.Parse(hex.Substring(start + 4, 2), System.Globalization.NumberStyles.HexNumber);
//			
//			return Color.FromArgb(a, r, g, b);
//		}
//		public static string ColorToHexString(Color color)
//		{
//			
//			
//			
//			byte[] bytes = new byte[3];
//			bytes[0] = color.R;
//			bytes[1] = color.G;
//			bytes[2] = color.B;
//			char[] chars = new char[bytes.Length * 2];
//			for (int i = 0; i < bytes.Length; i++)
//			{
//				int b = bytes[i];
//				chars[i * 2] = HexDigits[b >> 4];
//				chars[i * 2 + 1] = HexDigits[b & 0xF];
//			}
//			return new string(chars);
//		}
//		public static string ColorToHexString(string colorName)
//		{
//			if (String.IsNullOrEmpty(colorName))
//				return null;
//			SolidColorBrush col = (SolidColorBrush)new BrushConverter().ConvertFromString(colorName);
//			if (col == null) return null;
//			
//			Color color = col.Color;
//			byte[] bytes = new byte[3];
//			bytes[0] = color.R;
//			bytes[1] = color.G;
//			bytes[2] = color.B;
//			char[] chars = new char[bytes.Length*2];
//			for (int i = 0; i < bytes.Length; i++)
//			{
//				int b = bytes[i];
//				chars[i*2] = HexDigits[b >> 4];
//				chars[i*2 + 1] = HexDigits[b & 0xF];
//			}
//			return new string(chars);
//		}
		
		[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
		private static extern IntPtr GetForegroundWindow();
		
		[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
		
	}
}

